#!/usr/bin/env python
# _*_coding:utf-8_*_

"""
@author:gao
@file: testDemo.py
@time: 2018/09/{DAY}
"""
import matplotlib
from matplotlib import cm
import sys
import random
from matplotlib.dates import date2num, MinuteLocator, SecondLocator, DateFormatter
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from PyQt5 import QtCore, QtWidgets, QtGui
from matplotlib.ticker import MultipleLocator
from PyQt5.QtCore import *
from PyQt5 import QtCore, QtGui, QtWidgets
from matplotlib.ticker import FuncFormatter
from matplotlib.animation import FuncAnimation
from matplotlib.colors import ListedColormap, BoundaryNorm
from matplotlib.patches import Rectangle
from utils.color_util import *
from utils.re_util import sub_string
from utils.handle_coordinate_util import handle_coordinate
import matplotlib.colors as mcolors

import matplotlib.ticker as ticker
from scipy.interpolate import griddata
from scipy.stats import norm
import pandas as pd
import re
from utils.log_util import loggings

matplotlib.use('Qt5Agg')
# matplotlib的中文显示解决设置
matplotlib.rcParams["font.family"] = "simsun"  # 设置的此行，解决了中文的警告问题
matplotlib.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文标签
matplotlib.rcParams['axes.unicode_minus'] = False  # 设置支持负号
plt.rcParams['mathtext.fontset'] = 'cm'  # 设置支持负指数正常显示的设置


# 创建一个matplotlib图形绘制类
# FigureCanvas 画布
# Figure 图
# Axes 坐标轴(实际画图的地方)
class MyFigure(FigureCanvas):
    customSignal = pyqtSignal()
    global cb
    cb = None

    def __init__(self, width=10, height=10, dpi=120):
        # 第一步：创建一个创建Figure
        plt.ion()
        self.fig = Figure(figsize=(width, height), dpi=dpi)
        # 第二步：在父类中激活Figure窗口
        super(MyFigure, self).__init__(self.fig)  # 此句必不可少，否则不能显示图形
        self.axes = self.fig.add_subplot(1, 1, 1)

        # 设置四条边框不可见
        self.axes.set_autoscaley_on(True)
        self.axes.spines['top'].set_visible(False)
        self.axes.spines['right'].set_visible(False)
        self.axes.set_xticks([])
        self.axes.set_yticks([])
        # self.axes.grid()
        self.gic = None
        self.axes.cla()  # 清空坐标轴内的所有内容
        FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        self.curveObj = None  # draw object
        self.x_data = None
        self.y_data = None

    def clear(self):
        self.axes.cla()  # 清空坐标轴内的所有内容
        # self.axes.clf()  # 清空坐标轴内的所有内容
        global cb
        if cb:
            cb.remove()
            cb = None
        self.updatePlot()

    def show_grid(self, is_visibel):
        self.axes.grid(visible=is_visibel)

    def onclick(self, event):
        self.x_data = event.xdata
        self.y_data = event.ydata

    def show_spines(self):
        # 设置四条边框不可见
        self.axes.spines['top'].set_visible(True)
        self.axes.spines['right'].set_visible(True)
        self.axes.spines['bottom'].set_visible(True)
        self.axes.spines['left'].set_visible(True)

    def updatePlot(self):
        self.draw()

    def setSupTitle(self, title):
        self.fig.suptitle(title)

    def savefig(self, *args, **kwargs):
        self.fig.savefig(*args, **kwargs)

    def setXLim(self, x_min, x_max):
        self.axes.set_xlim(x_min, x_max)

    def setYLim(self, y_min, y_max):
        self.axes.set_ylim(y_min, y_max)

    def setXLabel(self, x_label="time of dataHandle generator"):
        self.axes.set_xlabel(x_label)

    def setYLabel(self, y_label="'random dataHandle value"):
        self.axes.set_ylabel(y_label)

    def setLegend(self, legend="string"):
        self.axes.legend(legend)

    def xlog(self):
        self.axes.semilogx()

    def ylog(self):
        self.axes.semilogy()

    def dup_remove_set(self, list_raw):
        result = []
        for sublist in list_raw:
            for sub in sublist:
                if sub not in result:
                    result.append(sub)
        return result

    def plot_curve(self, datax, datay, label, is_invert_y, is_log):
        if self.curveObj is None:
            # create draw object once
            self.curveObj, = self.axes.plot(np.array(datax), np.array(datay), label=label, picker=5)
        else:
            # update dataHandle of draw object
            self.axes.plot(np.array(datax), np.array(datay), label=label, picker=5)

        if is_invert_y:
            self.axes.invert_yaxis()
        if is_log:
            self.axes.set_yscale("log")
        if label:
            legend = self.axes.legend(loc=9, bbox_to_anchor=(0.3, 0.3), ncol=6, fancybox=False, shadow=False)
            legend.get_frame().set_facecolor('none')
            legend.get_frame().set_alpha(0)
        self.axes.legend(bbox_to_anchor=(0.6, 0.6), ncol=6, loc=9, borderaxespad=0)
        self.axes.get_legend().set_visible(False)
        self.draw()

    def plot_spot_curve(self, datax, datay, label):
        self.axes.relim()
        self.axes.autoscale_view()

        if self.curveObj is None:
            # create draw object once
            self.curveObj, = self.axes.plot(np.array(datax), np.array(datay), color='r', linestyle='-', marker='o',
                                            linewidth=2, label=label)
        else:
            # update dataHandle of draw object
            self.axes.plot(np.array(datax), np.array(datay), color='r', linestyle='-', marker='o', linewidth=2,
                           label=label)
        if label:
            self.axes.legend()
        self.draw()
        # self.axes.flush_events()

    def plot_hist(self, data, label, label1):
        n, bins, patches = self.axes.hist(np.array(data), bins=60, density=False, edgecolor="r",
                                          alpha=0.7, histtype="bar", label=f"{label1}_{label}")
        mu = np.mean(data)
        sigma = np.std(data)
        bins = bins.astype("float")
        y = norm.pdf(bins, mu, sigma)
        self.axes.plot(bins, y, "b--")
        # self.axes.text(float(data[-1]) - 0.1, max(n) - 0.1, str(mu))
        # self.axes.text(float(data[-1]) - 0.1, max(n) - 0.5, str(sigma))
        self.axes.legend()
        self.draw()

    def get_z_data(self, x, y):
        z = (x ** 2 + y ** 5) * np.exp(-x ** 2 - y ** 2)
        z1 = np.exp(-(x - 1) ** 2 - (y - 1) ** 2)
        Z = (z - z1) * 2
        return Z

    def plot_contour(self, x_list, y_list, zlist):
        # 获得网格坐标矩阵
        xi = np.array(np.arange(np.min(x_list), np.max(x_list), 0.1), dtype=np.float)
        yi = np.array(np.arange(np.min(y_list), np.max(y_list), 0.1), dtype=np.float)
        X, Y = np.meshgrid(xi, yi)
        method = 'cubic'
        Z = griddata((x_list, y_list), np.array(zlist), (X, Y), method=method)
        # 绘制等高线
        cp = self.axes.contour(X, Y, Z, 10, colors="black", linewidths=0.5)
        # 绘制线条标注
        self.axes.clabel(cp, fontsize=9, inline=True)
        # 填充颜色
        cp = self.axes.contourf(X, Y, Z, 10, cmap="afmhot_r", alpha=0.5)
        global cb
        cb = self.fig.colorbar(cp, shrink=1)  # Add a colorbar to a plot
        self.axes.invert_yaxis()
        self.draw()

    def __highlight_cell(self, x, y, ax=None, **kwargs):
        rect = plt.Rectangle((x - .5, y - .5), 1, 1, fill=False, **kwargs)
        ax = ax or plt.gca()
        ax.add_patch(rect)
        return rect

    def plot_bin(self, data_array, pos_x, pos_y, pos_array):
        import copy
        colors = ['#FFFFFF', '#00ff00', '#ff0000']  # color list
        data_array1 = sorted(self.dup_remove_set(copy.deepcopy(data_array)))
        cmap = ListedColormap(colors)
        bounds = data_array1
        norms = BoundaryNorm(bounds, cmap.N - 1)
        data_array = np.array(data_array)
        pos_array = np.array(pos_array)
        # self.gic = self.axes.imshow(data_array, cmap=cmap, norm=norms, aspect='equal')  # 画图
        self.gic = self.axes.imshow(data_array, cmap=cmap, norm=norms, aspect='auto')  # 画图
        # self.gic = self.axes.matshow(data_array, cmap=cmap, norm=norms)  # 画图
        # 添加colorbar
        # self.fig.colorbar(self.gic)
        # 设置坐标的刻度不显示
        self.axes.set_xticks([])
        self.axes.set_yticks([])
        pos_x_list = [i for i in range(pos_x[0], pos_x[1] + 1)]  # 坐标刻度
        pos_y_list = [i for i in range(pos_y[0], pos_y[1] + 1)]
        self.axes.set_xticks(np.arange(len(pos_x_list)))
        # 设置x轴刻度间隔
        self.axes.set_yticks(np.arange(len(pos_y_list)))
        # 设置y轴刻度间隔
        self.axes.set_xticklabels(pos_x_list)
        # 设置x轴标签'''
        self.axes.set_yticklabels(pos_y_list)
        for i in range(len(pos_y_list)):
            for j in range(len(pos_x_list)):
                if data_array[i, j] == -300:  # 判断 没值就不写
                    continue
                else:
                    # ,pos_x_list[j], pos_y_list[i]
                    # 为单元格添加边框
                    cc = Rectangle((j - 0.5, i - 0.5), 1, 1,
                                   linewidth=1,
                                   edgecolor='black',
                                   facecolor='none')
                    self.axes.add_patch(cc)
        self.draw()

    def rect(self, pos):
        r = self.axes.Rectangle(pos - 0.5, 1, 1, facecolor="none", edgecolor="k", linewidth=2)
        self.axes.add_patch(r)

    def plot_contoutf(self, x=None, y=None, z=None):
        self.axes.contour(x, y, z)

    def get_color_list(self, data_array, para_list, color_list):
        color_new_list = []
        for i in data_array:
            if float(para_list[0][0]) <= float(i) < float(para_list[0][1]):
                color_new_list.append(para_list[0][2])
            elif float(para_list[1][0]) <= float(i) < float(para_list[1][1]):
                color_new_list.append(para_list[1][2])
            elif float(para_list[2][0]) < float(i) <= float(para_list[2][1]):
                color_new_list.append(para_list[2][2])
        return color_new_list

    def plot(self, data_array, color_list, para_list, pos_x, pos_y, pos_array, is_show_digit, is_correction_factor,
             correction_factor):
        try:
            global str_text
            import copy
            colors = color_list  # color list
            data_array1 = sorted(self.dup_remove_set(copy.deepcopy(data_array)))
            colors.insert(0, '#FFFFFF')
            cmap = ListedColormap(colors)
            bounds = data_array1
            norms = mcolors.BoundaryNorm(bounds, cmap.N)
            data_array = np.array(data_array)
            pos_array = np.array(pos_array)
            # self.gic = self.axes.imshow(data_array, cmap=cmap, norm=norms, aspect='equal')  # 画图
            self.gic = self.axes.imshow(data_array, cmap=cmap, norm=norms, aspect='auto')  # 画图
            # self.gic = self.axes.imshow(data_array, cmap="binary", norm=norms, aspect='auto')  # 画图
            # self.gic = self.axes.matshow(data_array, cmap=cmap, norm=norms)  # 画图
            # 添加colorbar
            global cb
            cb = self.fig.colorbar(self.gic)
            # ticks = cb.get_ticks()
            # print("length", len(ticks))
            # tick_locator = ticker.MaxNLocator(nbins=len(ticks))
            # cb.locator = tick_locator
            # # if np.min(data_array) == -300:
            # #     ticks[0] = float(ticks[1])/2
            # # else:
            # #     ticks[0] = np.min(data_array)
            # ticks[-1] = np.max(data_array)
            # print("ticks", ticks)
            # cb.set_ticks(ticks)
            # 设置坐标的刻度不显示
            self.axes.set_xticks([])
            self.axes.set_yticks([])
            pos_x_list = [i for i in range(pos_x[0], pos_x[1] + 1)]  # 坐标刻度
            pos_y_list = [i for i in range(pos_y[0], pos_y[1] + 1)]
            self.axes.set_xticks(np.arange(len(pos_x_list)))
            # 设置x轴刻度间隔
            self.axes.set_yticks(np.arange(len(pos_y_list)))
            # 设置y轴刻度间隔
            self.axes.set_xticklabels(pos_x_list)
            # 设置x轴标签'''
            self.axes.set_yticklabels(pos_y_list)
            for i in range(len(pos_y_list)):
                for j in range(len(pos_x_list)):
                    if data_array[i, j] == -300:  # 判断 没值就不写
                        continue
                    else:
                        # 为单元格添加边框
                        cc = Rectangle((j - 0.5, i - 0.5), 1, 1,
                                       linewidth=1,
                                       edgecolor='black',
                                       facecolor='none')
                        self.axes.add_patch(cc)
                    # 在方格中绘制坐标
                    if is_show_digit == 2:
                        if is_correction_factor == 2 and correction_factor:
                            str_text = str("%.7f" % (float(str(data_array[i, j])) * float(correction_factor)))
                        else:
                            if 1e-6 > abs(float(data_array[i, j])) or abs(float(data_array[i, j])) > 1e+8:
                                str_text = format(float(str(data_array[i, j])), ".3E")
                            else:
                                str_text = str("%.4f" % (float(str(data_array[i, j]))))
                            #
                        self.axes.text(j, i, str_text,
                                       ha="center", va="center", color="black",
                                       fontdict={'family': 'Times New Roman', 'size': 14})
            self.draw()
        except Exception as e:
            loggings.error("plot" + str(e))


class Matrix(QtWidgets.QWidget):
    sendSignal = pyqtSignal(object, object)
    spotSendSignal = pyqtSignal(object, object, object)
    lineInfoSignal = pyqtSignal(object)

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)
        self.canvas = MyFigure()
        self.vbl = QtWidgets.QVBoxLayout()
        self.ntb = NavigationToolbar(self.canvas, parent)
        self.vbl.addWidget(self.ntb)
        self.vbl.addWidget(self.canvas)
        self.setLayout(self.vbl)
        self.symbol = None
        self.graph_data = None
        self.canvas.mpl_connect("button_press_event", self.on_click)
        self.canvas.mpl_connect("pick_event", self.on_pick)

    def clear(self):
        self.canvas.clear()

    def on_pick(self, event):
        self.get_legend_text(event)

    def get_legend_text(self, event):
        line = event.artist
        line_list = self.canvas.axes.get_lines()
        legend = self.canvas.axes.get_legend()
        legend_texts = legend.get_texts()
        # legend_lines = legend.get_lines()
        if line:
            for line_ in line_list:
                line_.set_alpha(0.1)
            line.set_alpha(1)
            line_index = line_list.index(line)
            self.canvas.fig.canvas.draw_idle()
            self.lineInfoSignal.emit(legend_texts[line_index].get_text())

    def on_click(self, event):
        if event.xdata and event.ydata:
            text = self.ntb.locLabel.text()
            if "[" not in text:
                line_list = self.canvas.axes.get_lines()
                for line_ in line_list:
                    line_.set_alpha(1)
                self.canvas.fig.canvas.draw_idle()
                self.sendSignal.emit(event.xdata, event.ydata)
            else:
                x_coordinate, y_coordinate = handle_coordinate(event.xdata, event.ydata)
                result = sub_string(text)
                self.spotSendSignal.emit(x_coordinate, y_coordinate, result[0])

    def setX_label(self, x_label):
        self.canvas.setXLabel(x_label)

    def setY_label(self, y_label):
        self.canvas.setYLabel(y_label)

    def setSupTitle(self, title):
        self.symbol = title
        self.canvas.setSupTitle(title)

    def saveImage(self, file_name):
        self.canvas.savefig(file_name)

    def close(self):
        self.canvas.close()

    def show_grid(self, is_visibel=True):
        self.canvas.show_grid(is_visibel)

    def show_spines(self):
        self.canvas.show_spines()

    def xlogshow(self):
        self.canvas.xlog()

    def ylogshow(self):
        self.canvas.ylog()

    def setXLim(self, x_min, x_max):
        self.canvas.setXLim(x_min, x_max)

    def plot_spot_curve(self, x_data, y_data):
        self.canvas.plot_spot_curve(x_data, y_data, label=None)

    def setYLim(self, y_min, y_max):
        self.canvas.setYLim(y_min, y_max)

    def plot_bin(self, data_array, pos_x, pos_y, pos_array):
        self.clear()
        self.canvas.plot_bin(data_array, pos_x, pos_y, pos_array)

    def plot_contour(self, x_data, y_data, z_data):
        self.clear()
        self.canvas.plot_contour(x_data, y_data, z_data)

    def plot(self, data_array, color_list, para_list, pos_x, pos_y, pos_array, is_show_digit=None,
             is_correction_factor=None,
             correction_factor=None):
        self.clear()
        self.show_grid(False)
        self.canvas.plot(data_array, color_list, para_list, pos_x, pos_y, pos_array, is_show_digit,
                         is_correction_factor,
                         correction_factor)

    def set_colors(self, colors):
        self.canvas.axes.set_prop_cycle('color', colors)

    def plot_curve(self, x_data, y_data, label=None, is_invert_y=False, is_log=False):
        self.canvas.plot_curve(x_data, y_data, label, is_invert_y, is_log)

    def plot_hit(self, data, label, label1):
        self.canvas.plot_hist(data, label, label1)
